/* MIT License
 *
 * Copyright (c) 2012 Reuben Smith, Miami University
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.droidlike.vsig;


import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;


/**
 * World.
 * 
 * @author smithre5
 */
public class World extends AbstractAppState
{  
    /**
     * Creates the world spatial. This is the generic geometry on which the actual
     * simulation map is laid out. "Pretty" things should go here.
     * 
     * @param assetManager the AssetManager to use
     * 
     * @return a Geometry representing world surface and decorations
     */
    public static Geometry createGeometry(World world, AssetManager assetManager)
    {        
        Geometry worldSpatial = new Geometry("world");
        
        Quad worldMesh = new Quad(
            Math.abs(BOUNDS[0].x) + Math.abs(BOUNDS[1].x),
            Math.abs(BOUNDS[0].z) + Math.abs(BOUNDS[1].z)
        );
        
        // smithre5: This is to compensate for the current world texture being
        // only 32x32. The scaling factor should change if we move to a better
        // texture resolution. The scaling format is repeats per mile in feet
        // over each dimension.
        final float TEX_PER_MILE = 100.f;
        
        worldMesh.scaleTextureCoordinates(new Vector2f(
            (TEX_PER_MILE / 5280.f) * worldMesh.getWidth(),
            (TEX_PER_MILE / 5280.f) * worldMesh.getHeight()
        ));
        
        Texture worldTexture = assetManager.loadTexture("Textures/grass.png");
        worldTexture.setWrap(Texture.WrapMode.Repeat);
        
        Material worldMaterial = new Material(assetManager,
            "Common/MatDefs/Misc/ColoredTextured.j3md");
        worldMaterial.setTexture("ColorMap", worldTexture);
        worldMaterial.setColor("Color", ColorRGBA.Green);
        
        worldSpatial.setMesh(worldMesh);
        worldSpatial.setMaterial(worldMaterial);
        
        // Quads are created in XY plane; rotate into XZ plane.
        worldSpatial.rotate(-90.0f * FastMath.DEG_TO_RAD, 0, 0);
        // Moving center of spatial to (0, -5, 0). Moved spatial down to help
        // with Z-fighting.
        worldSpatial.setLocalTranslation(
            -(worldMesh.getWidth() / 2),  
            -0.5f,
            (worldMesh.getHeight() / 2)
        );
        
        return worldSpatial;
    }
    
    
    public World(PhysicsSpace space)
    {
        this.space = space;
    }
    
    
    @Override
    public void initialize(AppStateManager stateManager, Application app)
    {
        Simulation sim = (Simulation)app;
        
        super.initialize(stateManager, app);
        
        worldGeom = World.createGeometry(this, sim.getAssetManager());
        worldBody = new RigidBodyControl(0.0f);
        worldGeom.addControl(worldBody);
        sim.getScene3D().attachChild(worldGeom);
        
        roadsGeom = RoadGraph.createGeometry(sim.getGraph(), sim.getAssetManager());
        sim.getScene3D().attachChild(roadsGeom);
        
        space.add(worldGeom);
    }
    

    @Override
    public void update(float tpf)
    {
    }
    

    @Override
    public void cleanup()
    {
        super.cleanup();
    }
    
    
    /**
     * @return the World's visual geometry
     */
    public Geometry getGeometry()
    {
        return worldGeom;
    }
    
    
    /**
     * @return the World's physical control
     */
    public RigidBodyControl getPhysicalBody()
    {
        return worldBody;
    }
        
    
    public static final ColorRGBA SKY_COLOR =
        new ColorRGBA(0.392f, 0.584f, 0.929f, 1.f);

    /*
     * The first bound describes the minimums, second bound describes the
     * maximums. Units are in feet, so this describes a ~1 mi^2 region with
     * a ceiling of 250 ft. The floor is > 0 ft to prevent the camera going
     * into things.
     */
    public static final Vector3f[] BOUNDS = new Vector3f[]{
        new Vector3f(-2640.0f,  25.0f, -2640.0f),
        new Vector3f( 2640.0f, 250.0f,  2640.0f)
    };
    
    
    private PhysicsSpace space;
            
    private Geometry worldGeom;
    private RigidBodyControl worldBody;
    
    private Geometry roadsGeom;
}

